﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
using System.Configuration;
using System.Net;
using System.IO;
using WMM.Tapioca;
using WMM.Tapioca.Instance;
using WMM.Tapioca.Taxonomy;
using WMM.Tapioca.Validate;
using WMM.Tapioca.Linkbase;
using WMM.Tapioca.Utilities;

namespace WMM.Test.Tapioca
{
    /// <summary>
    /// This class executes the XBRL-CONF-CR3-2007-03-05 conformance test suite.
    /// </summary>
    /// <remarks>
    /// The test suite is driven by a document in the root of the conformance suite
    /// folder named "xbrl.xml". The root document is an XML document that contains
    /// a set of &lt;testcase&gt; elements, each of which references a separate
    /// test case document.
    /// </remarks>
    [TestClass]
    public class XDTCONFCR420091006Test
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        static XmlCachingResolver resolver;

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            bool useProxy = Boolean.Parse(ConfigurationManager.AppSettings["UseProxy"]);
            resolver = new XmlCachingResolver(true, useProxy);    
        }

		private int thisTestsPassed;

		public XDTCONFCR420091006Test()
		{
		}

		[TestMethod]
        [Description("XDT-CONF-CR4-2009-10-06")]
		public void XDTCONFCR420091006Testcases()
		{
			thisTestsPassed = 0;
			var conformanceXmlSource = ConfigurationManager.AppSettings["ConformanceXdt"];
			var conformanceXmlSourcePath = Path.GetDirectoryName(conformanceXmlSource);
			var conformanceXmlDocument = new XmlDocument();
			conformanceXmlDocument.Load(conformanceXmlSource);
			var TestcaseNodes = conformanceXmlDocument.SelectNodes("//testcase");

			foreach (XmlNode TestcaseNode in TestcaseNodes)
			{
				ExecuteTestcase(conformanceXmlSourcePath, TestcaseNode);
			}
		}

		/// <summary>
		/// Executes the test case referenced in the supplied test case node.
		/// </summary>
		/// <param name="ConformanceXmlSourcePath">
		/// The path to the conformance suite.
		/// </param>
		/// <param name="TestcaseNode">
		/// A reference to one of the &lt;testcase&gt; elements in the root test suiteb ocument.
		/// </param>
		private void ExecuteTestcase(string ConformanceXmlSourcePath, XmlNode TestcaseNode)
		{
			var uriAttribute = TestcaseNode.Attributes["uri"];
			var testcaseXmlSource = uriAttribute.Value;
			var testcaseXmlSourceFullPathBuilder = new StringBuilder();
			testcaseXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", ConformanceXmlSourcePath, Path.DirectorySeparatorChar, testcaseXmlSource);
			var testcaseXmlSourceFullPath = testcaseXmlSourceFullPathBuilder.ToString();
			var testcaseXmlSourceDirectory = Path.GetDirectoryName(testcaseXmlSourceFullPath);
			var testcaseXmlDocument = new XmlDocument();
			testcaseXmlDocument.Load(testcaseXmlSourceFullPath);
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(testcaseXmlDocument.NameTable);
            nsmgr.AddNamespace("c", "http://xbrl.org/2005/conformance");
            var variationNodes = testcaseXmlDocument.SelectNodes("//variation", nsmgr);

			foreach (XmlNode VariationNode in variationNodes)
			{
				ExecuteVariation(testcaseXmlSourceDirectory, VariationNode);
			}
		}

		//-------------------------------------------------------------------------------
		//-------------------------------------------------------------------------------
		private void ExecuteVariation(string TestcaseXmlSourceDirectory, XmlNode VariationNode)
		{
            XbrlException VariationException = null;
            bool Validated = true;

			var currentVariation = new TestVariation(VariationNode);

            if (currentVariation.isReadInstanceFirst)
            {
                if (string.IsNullOrEmpty(currentVariation.Instance) == true)
                    return;

                var instanceXmlSourceFullPathBuilder = new StringBuilder();
                instanceXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Instance);

                var instanceXmlSourceFullPath = instanceXmlSourceFullPathBuilder.ToString();

                try
                {
                    InstanceDocument newInstanceDocument = new InstanceDocument(instanceXmlSourceFullPath, resolver);
                    XbrlManager xbrlManager = new XbrlManager(newInstanceDocument);                    
                    xbrlManager.Validate();
                    Validated = newInstanceDocument.Dts.ValidatedInstance;
                }
                catch (Exception ex)
                {
                    log.Error("Error:", ex);
                    Validated = false;
                }
            }



            if (currentVariation.isReadXsdFirst || currentVariation.isReadLinkbaseFirst)
            {
                try
                {
                    DTS dts = null;
                    TaxonomySchema ts = null;

                    if (currentVariation.isReadXsdFirst)
                    {
                        if (!string.IsNullOrEmpty(currentVariation.Xsd))
                        {
                            var schemaXmlSourceFullPathBuilder = new StringBuilder();
                            schemaXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Xsd);

                            string XsdSourceFullPath = schemaXmlSourceFullPathBuilder.ToString();

                            ts = new TaxonomySchema(null, XsdSourceFullPath, null, "", resolver);
                            dts = new DTS(ts, resolver);
                        }
                    }                 
                    
                    if (currentVariation.isReadLinkbaseFirst)
                    {
                        if (!string.IsNullOrEmpty(currentVariation.Linkbase))
                        {                            
                            var linkbaseXmlSourceFullPathBuilder = new StringBuilder();
                            linkbaseXmlSourceFullPathBuilder.AppendFormat("{0}{1}{2}", TestcaseXmlSourceDirectory, Path.DirectorySeparatorChar, currentVariation.Linkbase);
                            string LinkbaseSourceFullPath = linkbaseXmlSourceFullPathBuilder.ToString();
                            LinkbaseDocument linkbase = new LinkbaseDocument(dts, null, "", LinkbaseSourceFullPath, "", resolver);
                            dts = new DTS(linkbase, resolver);
                           
                            log.Info("Creating LinkbaseDocument: " + linkbase.FileName);
                            dts.LinkbaseDocuments.Add(linkbase);
                        }
                    }
                    
                    XbrlManager xbrlManager = new XbrlManager(null);
                    ValidateLinkbases vlb = new ValidateLinkbases(dts);
                    ValidateDimensionalTaxonomy vd = new ValidateDimensionalTaxonomy(dts);

                    Validated = dts.ValidatedLinkbases && dts.ValidatedDimension;
                }
                catch (Exception ex)
                {
                    log.Error("Error:", ex);
                    Validated = false;
                }
            }


            if (Validated == true && !currentVariation.Error.Equals(""))
				AnnounceTestFailure(currentVariation);
            if (Validated == false && currentVariation.Error.Equals(""))
				AnnounceTestFailure(currentVariation, VariationException);
			thisTestsPassed++;
		}

		//-------------------------------------------------------------------------------
		//-------------------------------------------------------------------------------
		private void AnnounceTestFailure(TestVariation CurrentVariation, Exception VariationException)
		{
			var failMessage = new StringBuilder();

			failMessage.AppendFormat("Instance: {0}{1}", CurrentVariation.Instance, Environment.NewLine);
			failMessage.AppendFormat("Name: {0}{1}", CurrentVariation.Name, Environment.NewLine);
			failMessage.AppendFormat("Description: {0}", CurrentVariation.Description);
			if (VariationException != null)
			{
				failMessage.AppendFormat("{0}Exception Type: {1}{2}", Environment.NewLine, VariationException.GetType().ToString(), Environment.NewLine);
				failMessage.AppendFormat("Exception Description: {0}", VariationException.Message);
			}
			Assert.Fail(failMessage.ToString());
		}

		//-------------------------------------------------------------------------------
		//-------------------------------------------------------------------------------
		private void AnnounceTestFailure(TestVariation CurrentVariation)
		{
			AnnounceTestFailure(CurrentVariation, null);
		}
    }
}
